package org.example.common.strategy.factoty;

import org.example.common.strategy.Strategy;
import org.example.common.util.GenericsUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 策略工厂抽象基类
 */

public abstract class AbstractStrategyFactory<T, S extends Strategy<T>> implements InitializingBean, ApplicationContextAware {

    private final Class<S> strategyType = GenericsUtil.getTypeArgument(this.getClass(), 1);

    private Map<T, S> strategyMap;

    private ApplicationContext appContext;

    public S getStrategy(T id) {
        S strategy = strategyMap.get(id);
        Assert.notNull(strategy, "strategy id is not valid ");
        return strategy;
    }

    /**
     * 在初始化bean的时候执行该方法
     */
    @Override
    public void afterPropertiesSet() {
        // 获取 Spring 容器中，所有 S 类型的 Bean
        Collection<S> strategies = appContext.getBeansOfType(strategyType).values();
        long count = strategies.stream().map(Strategy::getId).distinct().count();
        Assert.isTrue(count == strategies.size(), strategyType + " Duplicate strategy id");
        // 创建指定大小的Map
        strategyMap = new HashMap<>(strategies.size());
        // 将所有 S 类型的 Bean 放入到 strategyMap 中
        for (final S strategy : strategies) {
            T id = strategy.getId();
            strategyMap.put(id, strategy);
        }
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.appContext = applicationContext;
    }
}
